<?php
/**
 *
 * @access public
 * @author Marcos Vinicius Pereira dos Santos, <marcos@eagletecnologia.com>
 * @version 1.0
 * @package PHPJasperReport
 * @subpackage Core
 * @since 1.0
 */
class ReportGenerator {

    /**     
     * @access protected
     * @var SimpleXMLElement
     */
    protected $xml = null;

    /**     
     * @access protected
     * @var String
     */
    protected $fileName = null;

    /**
     * @access protected
     * @var String
     */
    protected $defaultFontFamily = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $defaultFontSize = 10;

    /**
     * @access protected
     * @var String
     */
    protected $pageOrientation = "P";

    /**
     * @access protected
     * @var Integer
     */
    protected $pageWidth = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $pageHeight = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $columnWidth = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $topMargin = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $bottonMargin = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $leftMargin = null;

    /**
     * @access protected
     * @var Integer
     */
    protected $rightMargin = null;

    /**
     * @access protected
     * @var String
     */
    protected $whenNoDataType = "NoPages";

    /**
     * @access protected
     * @var Boolean
     */
    protected $titleNewPage = false;

    /**
     * @access protected
     * @var Boolean
     */
    protected $summaryNewPage = false;

    /**
     * @access protected
     * @var Boolean
     */
    protected $summaryWithPageHeaderAndFooter = false;

    /**
     * @access protected
     * @var Boolean
     */
    protected $ignorePagination = false;

    /**
     * @access protected
     * @var String
     */
    protected $sql = null;

    /**
     * @access protected
     * @var Array
     */
    protected $parameters = null;

    /**
     * @access protected
     * @var DataSet
     */
    protected $dataSets = null;

    /**
     * @access protected
     * @var Array
     */
    protected $dbConfig = null;

    /**
     * @access protected
     * @var String
     */
    protected $currentDataSet = "Default";

    /**
     * @access protected
     * @var Array
     */
    protected $variables = null;

    /**
     * @access protected
     * @var Array
     */
    protected $fields = null;

    /**
     * @access protected
     * @var Array
     */
    protected $bands = null;

    /**
     * @access protected
     * @var Array
     */
    protected $details = null;

    /**
     * @access protected
     * @var Array Group
     */
    protected $groups = null;
    
    /**
     * @access protected
     * @var Array
     */
    protected $record = null;

    /**
     * @access protected
     * @var Pattern
     */
    protected $pattern = null;

    /**
     * @access protected
     * @var    Band
     */
    protected $currentBand = null;

    /**
     * Armazena o timestamp em que a geração do relatório se iniciou.
     * @access protected
     * @var Integer
     */
    protected $timeStamp = null;

    /***************************************************************************
     *                               METHODS
     **************************************************************************/

    /**
     * @access public
     */
    public function  __construct() {
        $this->timeStamp = time();

        $this->pattern = new Pattern();

        $this->dataSets['Default'] = new DataSet();
        
    }

    /**
     * Método responsável por preparar a query sql para ser executada na base
     * de dados. Em outras palavras, este método realiza a substituição dos
     * parâmentros pelos valores correspondentes.
     * 
     * @access private
     * @param  String $sql
     * @return String
     */
    private function prepareSQL($sql){
        
        if(isset($this->parameters)){
            foreach($this->parameters as $key => $value){
                $sql = str_replace('$P{'.$key.'}', $value, $sql);
            }
        }        
        return $sql;
    }

    /**    
     * @access protected
     * @param  String $sql
     * @return PDOStatement
     */
    protected final function getData($sql){
        $returnValue = null;
        //echo $sql;
        $db = $this->dataBase->prepare($sql);
        
        if($db->execute()){
            $returnValue = $db;
        }
        
        return $returnValue;
    }

    /**     
     * @access public     
     * @param  SimpleXMLElement $xml
     * @return void
     */
    public function setXMLElement(SimpleXMLElement $xml){
        $this->xml = $xml;
    }

    /**     
     * @access public    
     * @param  String $name
     * @return void
     */
    public function setFileName($name){
        $this->fileName = $name;
    }    

    /**
     * @access private
     * @param  String $expression
     * @return String
     */
    
    private function replaceField($expression){
       
        $expression = str_replace('$F{', '$this->record["', $expression);
        $expression = str_replace('}', '"]', $expression);
        
        return $expression;
    }

    /**
     * @access private
     * @param  String $expression
     * @return String
     */
    private function replaceVariables($expression){

        switch($expression){
            case '$V{PAGE_NUMBER}':
                $expression = '{pnb}';
                break;
            
            case '"Page "+$V{PAGE_NUMBER}+" of"':
                $expression = str_replace('$V{PAGE_NUMBER}','{pnb}',PAGE_X_OF_Y);                
                break;

            case '" " + $V{PAGE_NUMBER}':
                $expression = "{nb}";
                break;

            default:
                $expression = str_replace('$V{', '$this->variables["', $expression);
                $expression = str_replace('}', '"]->value', $expression);
                break;
        }      

        return $expression;
    }

    /**
     * @access private
     * @param  String $expression
     * @return String
     */
    private function replaceParameters($expression){

        $expression = str_replace('$P{', '$this->parameters["', $expression);
        $expression = str_replace('}', '"]', $expression);
        
        return $expression;
    }

    /**
     * @access private
     * @param  String $expression
     * @return String
     */
    private function prepareExpression($expression){

        //Substituindo os fields.
        if(strpos($expression,'F{')){
            $expression = $this->replaceField($expression);
        }

        //Substituindo as variaveis.
        if(strpos($expression,'V{')){
            $expression = $this->replaceVariables($expression);
        }

        //Substituindo os parametros.
        if(strpos($expression,'P{')){
            $expression = $this->replaceParameters($expression);
        }

        return $expression;
    }

    /**     
     * @access protected     
     * @param  SimpleXMLElement $textField
     * @return Double
     */
    protected final function textFieldExpression(SimpleXMLElement $textField){

        $returnValue = $textField->textFieldExpression."";

        $class =  explode('.',$textField->textFieldExpression['class']);

        $returnValue = $this->prepareExpression($returnValue);
        $pattern = ($textField['pattern'])?$textField['pattern']:0;

        switch(array_pop($class)){            
            case "Date":
            case "Time":
                if($returnValue == "new java.util.Date()"){
                    $returnValue = date($pattern,$this->timeStamp);
                }else{
                    $returnValue = '$this->pattern->dateFormat('.$returnValue.',"'.$pattern.'")';
                }                
                break;                           

            case "String":                
                break;
            default:               
                if(is_numeric($var)){
                    $returnValue = $this->pattern->numberFormat($returnValue, $pattern);
                }else{
                    $returnValue = '$this->pattern->numberFormat('.$returnValue.',"'.$pattern.'")';
                }
                break;
        }
      
        return $returnValue;
    }       

    /**
     * Método responsável por seta o objeto de conexão com a base de dados.
     * 
     * @access public
     * @param  PDO $pdo
     * @return void
     */
    public final function setDBConfig(Array $dbConfig){
        $this->dbConfig = $dbConfig;
    }

    /**
     * Método responsável por converter uma cor em hexadecimal para RGB.
     * 
     * @access protected
     * @param  String $color String contendo a cor que deverá ser convertida.
     * @return array Array com a configuração da cor em RGB 'R,G,B'
     */
    protected final function hexTorgb($color) {

        if(!empty ($color)){
            if ($color[0] == '#'){
                $color = substr($color, 1);
            }
            if (strlen($color) == 6){
                list($r, $g, $b) = array($color[0].$color[1],
                        $color[2].$color[3],
                        $color[4].$color[5]);
            }elseif (strlen($color) == 3){
                list($r, $g, $b) = array($color[0].$color[0], $color[1].$color[1], $color[2].$color[2]);
            }else{
                return false;
            }
            $r = hexdec($r);
            $g = hexdec($g);
            $b = hexdec($b);

            return array($r, $g, $b);
        }
        return false;
    }

    /**
     * @access public
     * @param  array $params
     */
    public final function setReportParams(array $params){
        $this->parameters = $params;
    }
    
    /**
     * @access private
     * @param  SimpleXMLElement $variable
     * @return stdClass
     */
    private function prepareVariable(SimpleXMLElement $variable){
        $returnValue = new Variable();

        $returnValue->resetType = strtoupper($variable['resetType']);
        $returnValue->resetGroup = strtoupper($variable['resetGroup']);
        $returnValue->calculation = strtoupper($variable['calculation']);
        $returnValue->incrementType = strtoupper($variable['incrementType']);
        $returnValue->variableExpression = $this->prepareExpression($variable->variableExpression."");
        $returnValue->initialValueExpression = ($variable->initialValueExpression)?$variable->initialValueExpression."":0;
        $returnValue->value = $returnValue->initialValueExpression;
        
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $dataSet
     * @return DataSet
     */
    private function prepareSubDataSet(SimpleXMLElement $dataSet){
        $returnValue = new DataSet();

        $returnValue->name = $dataSet['name'].'';

        foreach($dataSet as $elementName => $element){
            switch($elementName){
                case "queryString":
                    $returnValue->sql = $element.'';
                break;

                case "parameter": 
                    $returnValue->parameters[$element['name'].''] = $element->defaultValueExpression.'';
                break;

                case "variable":
                    $returnValue->variables[$element['name'].''] = $this->prepareVariable($element);
                break;
            }
        }

        return $returnValue;
    } 

    /**
     * @access protected
     * @param  Integer $px
     * @return Integer
     */
    protected function convertUnit($px){
        return ($px);
    }

    /**
     * @access private
     * @param  Element $field
     * @param  SimpleXMLElement $element
     * @return void
     */
    private function loadConfigReportElement(Element &$field,SimpleXMLElement $element){
        
        $field->x = $this->convertUnit($element->reportElement['x']."");
        $field->y = $this->convertUnit($element->reportElement['y']."");
        $field->width = $this->convertUnit($element->reportElement['width']."");
        $field->height = $this->convertUnit($element->reportElement['height']."");
        
        $field->isPrintInFirstWholeBand = ($element->reportElement['isPrintInFirstWholeBand'])?true:false;
        $field->isPrintRepeatedValues = ($element->reportElement['isPrintRepeatedValues'])?false:true;
        $field->isPrintWhenDetailOverflows = ($element->reportElement['isPrintWhenDetailOverflows'])?true:false;
        $field->isRemoveLineWhenBlank = ($element->reportElement['isRemoveLineWhenBlank'])?true:false;
        
        $field->printWhenGroupChanges = ($element->reportElement['printWhenGroupChanges'])?$element->reportElement['printWhenGroupChanges']:'';

        if($element->reportElement->printWhenExpression){
            if(!empty ($element->reportElement->printWhenExpression)){
               $field->printWhenExpression = $this->prepareExpression($element->reportElement->printWhenExpression.'');
            }
        }

        //Verificando o modo de exibição do elemento.
        if($element->reportElement['mode'] && $element->reportElement['mode'] == "Opaque"){
           $field->opaque = true;
        }

        //Recuperando as cores que deve ser utilizadas no elemento.
        $colors = $this->getColors($element->reportElement);
        $field->backcolor = $colors['backcolor'];
        $field->forecolor = $colors['forecolor'];
    }

    /**
     * @access private
     * @param  SimpleXMLElement $reportElement
     * @return array
     */
    private function getColors(SimpleXMLElement $reportElement){
        //Recuperando a cor que deve ser utilizada no background.
        $backcolor = $this->hexTorgb($reportElement['backcolor']."");
        $backcolor = (!$backcolor)?array(255,255,255):$backcolor;

        //Recuperando a cor que deve ser utilizada no texto ou na borda.
        $forecolor = $this->hexTorgb($reportElement['forecolor']."");
        $forecolor = (!$forecolor)?array(0,0,0):$forecolor;

        return array("backcolor" => $backcolor, "forecolor" => $forecolor);
    }

    /**
     * @access private
     * @param  SimpleXMLElement $element
     * @return Array
     * @uses   ReportGenerator::hexTorgb()
     */
    private function getLineStyle(SimpleXMLElement $element) {
        $returnValue = array();
        $lineStyle = $element->graphicElement->pen['lineStyle'];

        if($lineStyle){
            switch($lineStyle){
                case "Solid": $lineStyle = 0; break;
                case "Dotted": $lineStyle = 1; break;
                case "Dashed": $lineStyle = 4; break;
                case "Double": $lineStyle = 0; break;
            }
        }else{
            $lineStyle = 0;
        }


        $lineWidth = $element->graphicElement->pen['lineWidth'];
        $lineWidth = ($lineWidth)?$lineWidth:1;

        $color = $this->hexTorgb($element->reportElement['forecolor']."");
        $color = (!$color)?array(0,0,0):$color;

        $returnValue = array("width" => $lineWidth, "color" => $color,'cap' => 'butt','join' => 'round','dash' => $lineStyle);
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $textElement
     * @return array
     */
    private function getAlignments(SimpleXMLElement $textElement){
        $align = substr($textElement['textAlignment']."",0,1);
        $valign = substr($textElement['verticalAlignment']."",0,1);

        $align = (empty ($align))?"L":$align;
        $valign = (empty ($valign))?"T":$valign;
        $valign = ($valign == "M")?"C":$valign;

        return array("halign" => $align,"valign" => $valign);
    }

    /**
     * @access private
     * @param  SimpleXMLElement $border
     * @return Array
     * @uses   ReportGenerator::hexTorgb()
     */
    private function getBorderBoxStyle(SimpleXMLElement $border){
        $returnValue = array();
        $lineStyle = $border['lineStyle'];

        if($lineStyle){
            switch($lineStyle){
                case "Solid": $lineStyle = 0; break;
                case "Dotted": $lineStyle = 1; break;
                case "Dashed": $lineStyle = 4; break;
                case "Double": $lineStyle = 0; break;
            }
        }else{
            $lineStyle = 0;
        }

        $lineWidth = $border['lineWidth'].'';
        $lineWidth = ($lineWidth)?$lineWidth:0.5;

        $color = $this->hexTorgb($border['lineColor']."");
        $color = (!$color)?array(0,0,0):$color;

        $returnValue = array("width" => $lineWidth, "color" => $color,'cap' => 'butt','join' => 'round','dash' => $lineStyle);
        return $returnValue;
    }

    /**
     * @access private
     */
    private function preparePageSettings(){
        $this->pageWidth = $this->xml['pageWidth'];
        $this->pageHeight = $this->xml['pageHeight'];
        $this->columnWidth  = $this->xml['columnWidth'];
        $this->topMargin = $this->xml['topMargin'];
        $this->bottomMargin = $this->xml['bottomMargin'];
        $this->leftMargin = $this->xml['leftMargin'];
        $this->rightMargin = $this->xml['rightMargin'];
        $this->pageOrientation = ($this->xml['orientation'])?substr($this->xml['orientation'],0,1):"P";
        $this->whenNoDataType = ($this->xml['whenNoDataType'])?$this->xml['whenNoDataType']."":"NoPages";
        $this->titleNewPage = ($this->xml['isTitleNewPage'])?true:false;
        $this->ignorePagination = ($this->xml['isIgnorePagination'])?true:false;
        $this->summaryNewPage = ($this->xml['isSummaryNewPage'])?true:false;
        $this->summaryWithPageHeaderAndFooter = ($this->xml['isSummaryWithPageHeaderAndFooter'])?true:false;
    }


    /**
     * @access private
     * @param  SimpleXMLElement $box
     * @return Box
     * @uses   Class Box
     * @uses   ReportGenerator::getBorderBoxStyle()
     */
    private function prepareBox(SimpleXMLElement $box){
        $returnValue = new Box();
       
        if($box->topPen) {            
            $returnValue->topPen = $this->getBorderBoxStyle($box->topPen);
        }

        if($box->leftPen) {
            $returnValue->leftPen = $this->getBorderBoxStyle($box->leftPen);
        }

        if($box->bottomPen) {
            $returnValue->bottomPen = $this->getBorderBoxStyle($box->bottomPen);
        }

        if($box->rightPen) {
            $returnValue->rightPen = $this->getBorderBoxStyle($box->rightPen);
        }
        
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $field
     * @return Text
     * @uses   Class Text
     * @uses   ReportGenerator::textFieldExpression()
     * @uses   ReportGenerator::convertUnit()
     * @uses   ReportGenerator::getAlignments()
     * @uses   ReportGenerator::getColors()
     * @uses   ReportGenerator::prepareBox()
     */
    private function prepareField(SimpleXMLElement $field){
        $type = $field->getName();
       
        if($type == "staticText"){
            $returnValue = new StaticText();
            $returnValue->text = $field->text."";
        }else{
            $returnValue = new TextField();
            $returnValue->fieldExpression = $this->textFieldExpression($field);
            $returnValue->stretchWhithOverflow = ($field['isStretchWithOverflow'])?true:false;
        }

        $this->loadConfigReportElement($returnValue,$field);

        //Recuperando os alinhamentos que devem ser utilizados.
        $alignments = $this->getAlignments($field->textElement);
        $returnValue->vAlign = $alignments['valign'];
        $returnValue->hAlign = $alignments['halign'];     
        
        if($field->textElement->font['size']){
            $returnValue->fontSize =  $field->textElement->font['size']."";
        }

        $returnValue->bold = ($field->textElement->font['isBold'] == "true")?true:false;
        $returnValue->italic = ($field->textElement->font['isItalic'] == "true")?true:false;
        $returnValue->underline = ($field->textElement->font['isUnderline'] == "true")?true:false;
        $returnValue->strikeThrongh = ($field->textElement->font['isStrikeThrough'] == "true")?true:false;

        if($field->box){
            $returnValue->box = $this->prepareBox($field->box);
        }
       
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $rectangle
     * @return Rectangle
     * @uses   Class Rectangle
     * @uses   ReportGenerator::convertUnit()
     * @uses   ReportGenerator::getLineStyle()
     * @uses   ReportGenerator::getColors()
     */
    private function prepareRectangle(SimpleXMLElement $rectangle){
        $returnValue = new Rectangle();

        $this->loadConfigReportElement($returnValue,$rectangle);
        
        if($rectangle['radius']){
            $returnValue->radius = $this->convertUnit($rectangle['radius']."");
        }

        $returnValue->lineStyle = $this->getLineStyle($rectangle);        

        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $line
     * @return Line
     * @uses   Class Line
     * @uses   ReportGenerator::convertUnit()
     * @uses   ReportGenerator::getLineStyle()
     */
    private function prepareLine(SimpleXMLElement $line){
        $returnValue = new Line();

        $this->loadConfigReportElement($returnValue,$line);
        
        $returnValue->direction = ($line['direction'])?true:false;
        
        $returnValue->lineStyle = $this->getLineStyle($line);

        return $returnValue;
    }

    /**
     * @access private
     * @param SimpleXMLElement $ellipse
     * @return Ellipse
     */
    private function prepareEllipse(SimpleXMLElement $ellipse){
        $returnValue = new Ellipse();

        $this->loadConfigReportElement($returnValue,$ellipse);

        $returnValue->lineStyle = $this->getLineStyle($ellipse);
     
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $image
     * @return Image
     * @uses   Class Image
     * @uses   ReportGenerator::convertUnit()
     */
    private function prepareImage(SimpleXMLElement $image){
        $returnValue = new Image();

        $this->loadConfigReportElement($returnValue,$image);
                
        $returnValue->file = str_replace('"','',$image->imageExpression);
        $returnValue->hAlign = ($image['hAlign'])?substr($image['hAlign'],0,1):"L";
        $returnValue->vAlign = ($image['vAlign'])?substr($image['vAlign'],0,1):"T";
        $returnValue->isLazy = ($image['isLazy'] == "true")?true:false;
        $returnValue->scaleImage = ($image['scaleImage'])?$image['scaleImage']."":"Clip";
        
        if($image->box){
            $returnValue->box = $this->prepareBox($field->box);
        }

        return $returnValue;
    }

    /**
     * @access private
     * @param SimpleXMLElement $frame
     * @return Frame
     */
    private function prepareFrame(SimpleXMLElement $frame){
        $returnValue = new Frame();

        $this->loadConfigReportElement($returnValue,$frame);

        $returnValue->box = $this->prepareBox($frame->box);

        foreach($frame as $elementName => $element){
            if($elementName != 'box' && $elementName != 'reportElement'){
                $element->reportElement['x'] += $returnValue->x;
                $element->reportElement['y'] += $returnValue->y;
                $returnValue->elements[] = $this->prepareElement($element, $elementName);
            }
        }

        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $subreport
     * @return Image
     * @uses   Class SubReport
     * @uses   ReportGenerator::convertUnit()
     */
    private function prepareSubReport(SimpleXMLElement $subreport){
        $returnValue = new SubReport();

        $this->loadConfigReportElement($returnValue,$subreport);
        
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $breakPoint
     * @return BreakPoint
     */
    private function prepareBreakPoint(SimpleXMLElement $breakPoint){
        $returnValue = new BreakPoint();
        
        if($breakPoint['type']){           
            $returnValue->breakType = $breakPoint['type'].'';
        }        
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $list
     * @return ListComponent
     */
    private function prepareListComponent(SimpleXMLElement $list){
        $returnValue = new ListComponent();
        
        $this->loadConfigReportElement($returnValue,$list);

        $returnValue->datasetRun->subDataset = $list->list->datasetRun['subDataset'].'';        
        $returnValue->datasetRun->parametersMapExpression = ($list->list->datasetRum->parametersMapExpression)?$list->list->datasetRum->parametersMapExpression:null;

        //Recuperando os fields que compoem o elemento list.
        $aux = get_object_vars($list->list->listContents);
        
        //Despresando o primeiro elemento do array.
        array_shift($aux);
      
        foreach($aux as $elementName => $element){

            //Caso $element seja um vetor de outros elementos.
            if(is_array($element)){
                foreach($element as $elem){
                    $elem->reportElement['x'] += $returnValue->x;
                    $elem->reportElement['y'] += $returnValue->y;
                    $returnValue->listComponents[] = $this->prepareElement($elem, $elementName);
                }
            }else{
                $element->reportElement['x'] += $returnValue->x;
                $element->reportElement['y'] += $returnValue->y;
                $returnValue->listComponents[] = $this->prepareElement($element, $elementName);
            }
        }
        
        return $returnValue;
    }

    /**
     * @access private
     * @param SimpleXMLElement $element
     * @param String $elementName
     * @return Element
     */
    private function prepareElement(SimpleXMLElement $element,$elementName){
        $returnValue = null;

        switch($elementName){
            case "staticText":
                $returnValue = $this->prepareField($element);
            break;

            case "rectangle":
                $returnValue = $this->prepareRectangle($element);
            break;

            case "line":
                $returnValue = $this->prepareLine($element);
            break;

            case "textField":
                $returnValue = $this->prepareField($element);
            break;

            case "ellipse":
                $returnValue = $this->prepareEllipse($element);
            break;

            case "image":
                $returnValue = $this->prepareImage($element);
            break;

            case "frame":
                $returnValue = $this->prepareFrame($element);
            break;

            case "subreport":
                $returnValue = $this->prepareSubReport($element);
            break;

            case "break":
                $returnValue = $this->prepareBreakPoint($element);
            break;

            case "componentElement":                
                $returnValue = $this->prepareListComponent($element);
            break;

            default:               
            break;
        }
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $band
     * @return Band
     * @uses   Class Band
     * @uses   ReportGenerator::prepareElement()
     */
    private function prepareBand(SimpleXMLElement $band){
        $returnValue = new Band();
        $returnValue->name = $band->getName();
        
        $returnValue->height = $band->band['height']."";
        $returnValue->printWhenExpression = $band->printWhenExpression;

        if($returnValue->printWhenExpression){
            if(!empty ($returnValue->printWhenExpression)){
               $returnValue->printWhenExpression = $this->prepareExpression($returnValue->printWhenExpression.'');
            }
        }

        $obj = $band->children()->children();
        
        foreach($obj as $elementName => $element){
            if($elementName != 'printWhenExpression'){
                $returnValue->items[] = $this->prepareElement($element, $elementName);
            }
        }
       
        return $returnValue;
    }

    /**
     * @access private
     * @param  SimpleXMLElement $group
     * @return Group
     */
    private function prepareGroup(SimpleXMLElement $group){
        $returnValue = new Group();
        
        $returnValue->name = $group['name']."";
        $returnValue->expression = substr($group->groupExpression,3,-1);
        $returnValue->value = "";
        $returnValue->drawHeader = true;
        $returnValue->drawFooter = false;
        $returnValue->reprintHeaderOnEachPage = ($group['isReprintHeaderOnEachPage'])?true:false;
        $returnValue->resetPageNumber = ($group['isResetPageNumber'])?true:false;
        $returnValue->startNewPage = ($group['isStartNewPage'])?true:false;
        $returnValue->startNewColumn = ($group['isStartNewColumn'])?true:false;
        $returnValue->footerPosition = $group['footerPosition']."";
        $returnValue->keepTogether = ($group['keepTogether'])?true:false;

        if($group->groupHeader){
            $returnValue->header = $this->prepareBand($group->groupHeader);
        }

        if($group->groupFooter){
            $returnValue->footer = $this->prepareBand($group->groupFooter);
        }

        return $returnValue;
    }

    /**
     * @access private
     * @return void
     */
    private function prepareReport(){
        
        foreach($this->xml as $elementName => $element){
            switch($elementName){
                case "property":break;
                case "subDataset":
                    $this->dataSets[$element['name'].''] = $this->prepareSubDataSet($element);
                break;
                case "parameter": 
                    $this->dataSets['Default']->parameters[$element['name'].''] = $element->defaultValueExpression.'';
                break;
                     
                case "field":break;

                case "queryString": $this->dataSets['Default']->sql = $element.''; break;
            
                case "variable":                    
                   $this->dataSets['Default']->variables[$element['name'].''] = $this->prepareVariable($element);
                break;

                case "group": 
                    $this->groups[] = $this->prepareGroup($element);
                break;
            
                default:                   
                    $this->bands[$elementName] = $this->prepareBand($element);
                break;
            }
        }

        //Configurando o acesso a base de dados do dataSet default
        $this->dataSets['Default']->setDBConfig($this->dbConfig);
    }

    /**
     * @access protected
     * @param  Element $element
     */
    protected function updateElementHeightByChildrenElementHeight(&$parent,Element $children){
        $yFinalElement = $children->y +$children->height;
        
        $yFinalBand = $parent->y +$parent->height;
        
        //Se a altura no elemento for superior a da band entao atualiza
        if($yFinalElement > $yFinalBand){            
            $parent->height += ($yFinalElement - $yFinalBand);
        }
    }

    /**
     * Método responsável por iniciar o processamento do relatório.
     * @access protected
     * @return void
     */
    protected function init(){
        $this->preparePageSettings();
        $this->prepareReport();
    }
}
?>